#pragma once

#include<iostream>
#include"Sem.hpp"
#include"Mutex.hpp"
#include<vector>

template<class T>
class RingQueue
{
public:
    RingQueue(int capacity = 5)
        :_capacity(capacity)
        ,_sem_space(capacity)
        ,_sem_data(0)
        ,_c_index(0)
        ,_p_index(0)
        ,_rq(capacity)
    { }

    void EnQueue(const T& in)
    {
        _sem_space.P();
        {
            LockGuard lock_guard(&_p_lock);
            _rq[_p_index++] = in;
            _p_index %= _capacity;
        }
        _sem_data.V();
    }

    void Pop(T* out)
    {
        _sem_data.P();
        {
            LockGuard lock_guard(&_c_lock);
            *out = _rq[_c_index++];
            _c_index %= _capacity;
        }
        _sem_space.V();
    }

private:
    Mutex _p_lock;
    Mutex _c_lock;
    Sem _sem_data;
    Sem _sem_space;
    int _c_index;
    int _p_index;
    int _capacity;
    std::vector<T> _rq;
};